#install.packages("knitr")
#install.packages("grid")
#install.packages("MLRMPA")
#install.packages("dprep")
#install.packages("normalr")
#install.packages("ggcorrplot")
#install.packages("RColorBrewer")
#install.packages("rgdal")
#install.packages("jsonlite")
#install.packages("RColorBrewer")
install.packages("readr")
library(gridExtra)
library(dplyr)
library(lubridate)
library(magrittr)
library(ggplot2)
library(tidyr)
library(knitr)
library(normalr)
library(ggcorrplot)
library(leaflet)
library(plotly)
library(RColorBrewer)
library(readr)
#library(jsonlite)
#library(rgdal)
#library(wesanderson)
#library(MLRMPA)
#??src_mysql
my_db <- src_mysql(
dbname = "covid",
host = "localhost",
user = "root",
password = "1234"
)
my_db
src: mysql 8.0.21 [root@localhost:/covid]
tbls: covid_confirmed_yearly, covid_deaths_yearly, covid_recovered_yearly, covid_thailand_updated, covid_us, covid19_confirmed_global, covid19_deaths_global,
covid19_recovered_global, full_datas, gdp, gdp19, healthranking, imf-country, owid-covid-data, population, pornhub, sars_2003, world_temp
##import data
df_conf <- tbl(my_db, sql("select * from covid_confirmed_yearly"))
df_conf <- as.data.frame(df_conf)
df_conf
df_deaths <- tbl(my_db, sql("select * from covid_deaths_yearly"))
df_deaths <- as.data.frame(df_deaths)
df_deaths
df_recover <- tbl(my_db, sql("select * from covid_recovered_yearly"))
df_recover <- as.data.frame(df_recover)
df_recover
##check the time frame of the data
n.col <- ncol(df_conf)
dates <- names(df_conf)[5:n.col]%>% mdy()
range(dates)
min.date <- min(dates)
max.date <- max(dates)
min.date.txt <- min.date %>% format('%d %b %Y')
max.date.txt <- max.date %>% format('%d %b %Y')
#clean data
cleanData <- function(data) {
## remove some columns
data %<>% select(-c(Province.State, Lat, Long)) %>% rename(country=Country.Region)
## convert from wide to long format
data %<>% gather(key=date, value=count, -country)
## convert from character to date
data %<>% mutate(date = date %>% mdy())
## aggregate by country
data %<>% group_by(country, date) %>% summarise(count=sum(count, na.rm=T)) %>% as.data.frame()
return(data)
}
## clean the three data sets
data.confirmed <- df_conf %>% cleanData() %>% rename(confirmed=count)
data.deaths <- df_deaths %>% cleanData() %>% rename(deaths=count)
data.recovered <- df_recover %>% cleanData() %>% rename(recovered=count)
data <- data.confirmed %>% merge(data.deaths, all=T) %>% merge(data.recovered, all=T)
data
## countries/regions with confirmed cases, excl. cruise ships
countries <- data %>% pull(country) %>% setdiff('Cruise Ship')
data
data.world <- data %>% group_by(date) %>%
summarise(country='World',
confirmed = sum(confirmed, na.rm=T),
deaths = sum(deaths, na.rm=T),
recovered = sum(recovered, na.rm=T))
data %<>% rbind(data.world)
data
data %<>% mutate(current.confirmed = confirmed - deaths - recovered)
View(data)
x <- raw.confirmed
x$confirmed <- x[, ncol(x)]
x %<>% select(c(Country.Region, Province.State, Lat, Long, confirmed)) %>%
mutate(txt=paste0(Country.Region, ' - ', Province.State, ': ', confirmed))
m <- leaflet(width=1200, height=800) %>% addTiles()
# circle marker (units in pixels)
m %<>% addCircleMarkers(x$Long, x$Lat,
# radius=2+log2(x$confirmed),
radius=0.03*sqrt(x$confirmed),
stroke=F,
color='red', fillOpacity=0.3,
label=x$txt)
# world
m
## China
m %>% setView(95, 35, zoom=4)
## Australia and New Zealand
m %>% setView(135, -27, zoom=4)
## US and Canada
m %>% setView(-105, 40, zoom=4)
## Europe
m %>% setView(10, 50, zoom=4)
#rate
data %<>% arrange(country, date)
n <- nrow(data)
day1 <- min(data$date)
data %<>% mutate(new.confirmed = ifelse(date == day1, NA, confirmed - lag(confirmed, n=1)),
new.deaths = ifelse(date == day1, NA, deaths - lag(deaths, n=1)),
new.recovered = ifelse(date == day1, NA, recovered - lag(recovered, n=1)))
data %<>% mutate(new.confirmed = ifelse(new.confirmed < 0, 0, new.confirmed),
new.deaths = ifelse(new.deaths < 0, 0, new.deaths),
new.recovered = ifelse(new.recovered < 0, 0, new.recovered))
## death rate based on total deaths and recovered cases
data %<>% mutate(rate.upper = (100 * deaths / (deaths + recovered)) %>% round(1),
rate.upper = ifelse(is.nan(rate.upper), 0, rate.upper))
## lower bound: death rate based on total confirmed cases
data %<>% mutate(rate.lower = (100 * deaths / confirmed) %>% round(1),
rate.lower = ifelse(is.nan(rate.lower), 0, rate.lower))
## death rate based on the number of death/recovered on every single day
data %<>% mutate(rate.daily = (100 * new.deaths / (new.deaths + new.recovered)) %>% round(1),
rate.daily = ifelse(is.nan(rate.daily), 0, rate.daily))
View(data)
## convert from wide to long format
data.long <- data %>%
select(c(country, date, confirmed, current.confirmed, recovered, deaths)) %>%
gather(key=type, value=count, -c(country, date))
## set factor levels to show them in a desirable order
data.long %<>% mutate(type=recode_factor(type, confirmed='Total Confirmed',
current.confirmed='Current Confirmed',
recovered='Recovered',
deaths='Deaths'))
View(data.long)
##Number of case World
world <- filter(data.long,country == 'World')
plot1 <- world %>% filter(type != 'Total Confirmed') %>%
ggplot(aes(x=date, y=count)) +
geom_area(aes(fill=type), alpha=0.5) +
labs(title=paste0('Numbers of Cases Worldwide - ', max.date.txt)) +
scale_fill_manual(values=c('red', 'green', 'black')) +
theme(legend.title=element_blank(), legend.position='bottom',
plot.title = element_text(size=7),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.key.size=unit(0.2, 'cm'),
legend.text=element_text(size=6),
axis.text=element_text(size=7),
axis.text.x=element_text(angle=45, hjust=1))
plot2 <- world %>%
ggplot(aes(x=date, y=count)) +
geom_line(aes(color=type)) +
labs(title=paste0('Numbers of Cases Worldwide (log scale) - ', max.date.txt)) +
scale_color_manual(values=c('purple', 'red', 'green', 'black')) +
theme(legend.title=element_blank(), legend.position='bottom',
plot.title = element_text(size=7),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.key.size=unit(0.2, 'cm'),
legend.text=element_text(size=6),
axis.text=element_text(size=7),
axis.text.x=element_text(angle=45, hjust=1)) +
scale_y_continuous(trans='log10')
## show two plots side by side
grid.arrange(plot1, plot2, ncol=2)
gly.plot2 <- ggplotly(plot2)
gly.plot2
## Current Confirmed Cases
data.world <- data %>% filter(country=='World')
n <- nrow(data.world)
plot1 <- ggplot(data.world, aes(x=date, y=current.confirmed)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Current Confirmed Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot2 <- ggplot(data.world, aes(x=date, y=new.confirmed)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Daily New Confirmed Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
## show two plots side by side
grid.arrange(plot1, plot2, ncol=2)
## a scatter plot with a smoothed line and vertical x-axis labels
plot1 <- ggplot(data.world, aes(x=date, y=deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot2 <- ggplot(data.world, aes(x=date, y=recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot3 <- ggplot(data.world, aes(x=date, y=new.deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot4 <- ggplot(data.world, aes(x=date, y=new.recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
## show four plots together, with 2 plots in each row
grid.arrange(plot1, plot2, plot3, plot4, nrow=2)
## convert from wide to long format, for drawing area plots
rates.long <- data %>%
select(c(country, date, rate.upper, rate.lower, rate.daily)) %>%
gather(key=type, value=count, -c(country, date))
# set factor levels to show them in a desirable order
rates.long %<>% mutate(type=recode_factor(type, rate.daily='Daily',
rate.upper='Upper bound',
rate.lower = 'Lower bound'))
#View(rates.long)
g <- rates.long %>% filter(country == "World") %>%
ggplot(aes(x = date, y = count, color = type)) +
geom_line() +
xlab("") + ylab("Death Rate (%)")
g
gly.death <- ggplotly(g)
gly.death
## ranking by confirmed cases
data.latest.all <- data %>% filter(date == max(date)) %>%
select(country, date,confirmed, new.confirmed, current.confirmed,
recovered, deaths, new.deaths, death.rate=rate.lower) %>%
mutate(ranking = dense_rank(desc(confirmed))) %>%
arrange(ranking)
View(data.latest.all)
k <- 20
## top 20 countries: 21 incl. 'World'
top.countries <- data.latest.all %>% filter(ranking <= k + 1) %>%
arrange(ranking) %>% pull(country) %>% as.character()
top.countries %>% setdiff('World') %>% print()
data.latest <- data.latest.all %>% filter(!is.na(country)) %>%
mutate(country=ifelse(ranking <= k + 1, as.character(country), 'Others')) %>%
mutate(country=country %>% factor(levels=c(top.countries, 'Others')))
data.latest %<>% group_by(country) %>%
summarise(confirmed=sum(confirmed), new.confirmed=sum(new.confirmed),
current.confirmed=sum(current.confirmed),
recovered=sum(recovered), deaths=sum(deaths), new.deaths=sum(new.deaths)) %>%
mutate(death.rate=(100 * deaths/confirmed) %>% round(1))
data.latest
data.latest %<>% select(c(country, confirmed, deaths, death.rate,
new.confirmed, new.deaths, current.confirmed,recovered)) %>%
mutate(recover.rate=(100 * recovered/confirmed) %>% round(1))
data.latest
df_pop <- tbl(my_db, sql("select * from population "))
df_pop <- as.data.frame(df_pop)
df_pop <- rename(df_pop,"country"="Country")
# Add World Population
world_pop <- sum(df_pop$`Population (2020)`)
df_pop[nrow(df_pop) + 1,] = c("World", world_pop)
# Add Other Countries Population
top_pop <- filter(df_pop, df_pop$country %in% top.countries & df_pop$country != "World")
top_pop <- sum(top_pop$`Population (2020)` %>% as.numeric())
others_pop <- (world_pop - top_pop)
df_pop[nrow(df_pop) + 1,] = c("Others", others_pop)
#View(df_pop)
data.latest <- merge(x = data.latest, y = df_pop, by = "country", all.x = TRUE)
data.latest
data.latest <- rename(data.latest,"population" = "Population (2020)")
data.latest$population <- data.latest$population %>% as.numeric()
data.latest <- data.latest %>%
select(c(country, confirmed, deaths, death.rate,
new.confirmed, new.deaths,
current.confirmed, recovered, recover.rate, population)) %>%
mutate(confirm.rate = (100 * confirmed / population) %>% round(1))
data.latest
data.latest %>% mutate(death.rate=death.rate %>% format(nsmall=1) %>% paste0('%'))
## convert from wide to long format, for drawing area plots
data.latest.long <- data.latest %>% filter(country!='World') %>%
gather(key=type, value=count, -country)
## set factor levels to show them with proper text and in a desirable order
data.latest.long %<>% mutate(type=recode_factor(type,
confirmed='Total Confirmed',
deaths='Total Deaths',
death.rate='Death Rate (%)',
new.confirmed='New Confirmed (compared with one day before)',
new.deaths='New Deaths (compared with one day before)',
current.confirmed='Current Confirmed',
recover.rate = 'Recover Rate(%)',
confirm.rate = 'Confirmed Rate(%)'))
#View(data.latest.long)
data.one.dem <- filter(data.latest.long,type=='Total Confirmed'
| type=='Total Deaths'
| type=='Current Confirmed')
data.two.dem <- filter(data.latest.long,type=='Death Rate (%)'
| type=='New Confirmed (compared with one day before)'
| type=='New Deaths (compared with one day before)'
| type=='Recover Rate(%)'
| type=='Confirmed Rate(%)')
data.two.dem
## bar chart
data.one.dem %>% ggplot(aes(x=country, y=count, fill=country, group=country)) +
geom_bar(stat='identity') +
geom_text(aes(label=count, y=count), size=3, vjust=0) +
xlab('') + ylab('') +
labs(title=paste0('Top 20 Countries with Most Confirmed Cases - ', max.date.txt)) +
scale_fill_discrete(name='Country', labels=aes(count)) +
theme(legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size=13),
axis.text=element_text(size=8),
axis.text.x=element_text(angle=45, hjust=1)) +
facet_wrap(~type, ncol=1, scales='free_y')
data.two.dem %>% ggplot(aes(x=country, y=count, fill=country, group=country)) +
geom_bar(stat='identity') +
geom_text(aes(label=count, y=count), size=3, vjust=0) +
xlab('') + ylab('') +
labs(title=paste0('Top 20 Countries with Most Confirmed Cases - ', max.date.txt)) +
scale_fill_discrete(name='Country', labels=aes(count)) +
theme(legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size=13),
axis.text=element_text(size=8),
axis.text.x=element_text(angle=45, hjust=1)) +
facet_wrap(~type, ncol=1, scales='free_y')
##GDP
df_gdp <- tbl(my_db, sql("select * from gdp"))
df_gdp <- as.data.frame(df_gdp)
df_gdp <- rename(df_gdp,"country"="Real GDP growth (Annual percent change)")
df_gdp <- select(df_gdp,c("country","2012","2013","2014","2015","2016","2017","2018","2019","2020","2021"))
df_gdp
df_gdp2019 <- tbl(my_db, sql("select * from gdp19"))
df_gdp2019 <- as.data.frame(df_gdp2019)
df_gdp2019
#healthranking
df_healt <- tbl(my_db, sql("select * from healthranking"))
df_healt <- as.data.frame(df_healt)
df_healt <- select(df_healt,c("country","healthCareIndex"))
View(df_healt)
#Top20Pornhub
df_pornhub <- tbl(my_db, sql("select * from Pornhub"))
df_pornhub <- as.data.frame(df_pornhub)
df_pornhub
#temp
df_temp <- tbl(my_db, sql("select * from world_temp"))
df_temp <- as.data.frame(df_temp)
df_temp$Country[df_temp$Country == "United States"] <- "US"
df_city <- select(df_temp,c("Country","City")) %>%
rename(country=Country) %>%
rename(city=City)
numofcity <- aggregate(city ~ country, data = df_city, length)
df_temp <- select(df_temp,c("Country","Avg_Year")) %>%
rename(country=Country)
View(df_temp)
#df_temp <- data.frame(country=df_temp[,1],avg=rowMeans(df_temp[,-1]))
df_temp <- df_temp %<>% group_by(country) %>% summarise(avg_temp = mean(Avg_Year,na.rm = TRUE)%>% round(1))
df_temp
#display.brewer.all()
df_temp.all <- df_temp %>% merge(data.latest.all)
View(df_temp.all)
df_temp_top.all <- df_temp.all %>% filter(country %in% top.countries) %>%
mutate(ranking = ranking - 1) %>%
arrange(ranking)
View(df_temp_top)
g_temp_top <- df_temp_top %>%
ggplot(aes(x = reorder(country, ranking), y = avg_temp, fill = avg_temp)) +
labs(title=paste0("Temperature in Top 20 countries"), subtitle = "Average Temperature in Top 20 countries with most confirmed cases (
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KI2luc3RhbGwucGFja2FnZXMoImdyaWQiKQ0KI2luc3RhbGwucGFja2FnZXMoIk1MUk1QQSIpDQojaW5zdGFsbC5wYWNrYWdlcygiZHByZXAiKQ0KI2luc3RhbGwucGFja2FnZXMoIm5vcm1hbHIiKQ0KI2luc3RhbGwucGFja2FnZXMoImdnY29ycnBsb3QiKQ0KI2luc3RhbGwucGFja2FnZXMoIlJDb2xvckJyZXdlciIpDQojaW5zdGFsbC5wYWNrYWdlcygicmdkYWwiKQ0KI2luc3RhbGwucGFja2FnZXMoImpzb25saXRlIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQ0KaW5zdGFsbC5wYWNrYWdlcygicmVhZHIiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KG5vcm1hbHIpDQpsaWJyYXJ5KGdnY29ycnBsb3QpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeShyZWFkcikNCiNsaWJyYXJ5KGpzb25saXRlKQ0KDQojbGlicmFyeShyZ2RhbCkNCiNsaWJyYXJ5KHdlc2FuZGVyc29uKQ0KI2xpYnJhcnkoTUxSTVBBKQ0KDQojPz9zcmNfbXlzcWwNCm15X2RiIDwtIHNyY19teXNxbCgNCiAgZGJuYW1lID0gImNvdmlkIiwNCiAgaG9zdCA9ICJsb2NhbGhvc3QiLA0KICB1c2VyID0gInJvb3QiLA0KICBwYXNzd29yZCA9ICIxMjM0Ig0KKQ0KbXlfZGINCg0KIyNpbXBvcnQgZGF0YQ0KZGZfY29uZiA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZF9jb25maXJtZWRfeWVhcmx5IikpDQpkZl9jb25mIDwtIGFzLmRhdGEuZnJhbWUoZGZfY29uZikNCmRmX2NvbmYNCmRmX2RlYXRocyA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZF9kZWF0aHNfeWVhcmx5IikpDQpkZl9kZWF0aHMgPC0gYXMuZGF0YS5mcmFtZShkZl9kZWF0aHMpDQpkZl9kZWF0aHMNCmRmX3JlY292ZXIgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gY292aWRfcmVjb3ZlcmVkX3llYXJseSIpKQ0KZGZfcmVjb3ZlciA8LSBhcy5kYXRhLmZyYW1lKGRmX3JlY292ZXIpDQpkZl9yZWNvdmVyDQpgYGANCmBgYHtyfQ0KIyNjaGVjayB0aGUgdGltZSBmcmFtZSBvZiB0aGUgZGF0YQ0Kbi5jb2wgPC0gbmNvbChkZl9jb25mKQ0KZGF0ZXMgPC0gbmFtZXMoZGZfY29uZilbNTpuLmNvbF0lPiUgbWR5KCkNCnJhbmdlKGRhdGVzKQ0KbWluLmRhdGUgPC0gbWluKGRhdGVzKQ0KbWF4LmRhdGUgPC0gbWF4KGRhdGVzKQ0KbWluLmRhdGUudHh0IDwtIG1pbi5kYXRlICU+JSBmb3JtYXQoJyVkICViICVZJykNCm1heC5kYXRlLnR4dCA8LSBtYXguZGF0ZSAlPiUgZm9ybWF0KCclZCAlYiAlWScpDQpgYGANCmBgYHtyfQ0KI2NsZWFuIGRhdGENCmNsZWFuRGF0YSA8LSBmdW5jdGlvbihkYXRhKSB7DQogICMjIHJlbW92ZSBzb21lIGNvbHVtbnMNCiAgZGF0YSAlPD4lIHNlbGVjdCgtYyhQcm92aW5jZS5TdGF0ZSwgTGF0LCBMb25nKSkgJT4lIHJlbmFtZShjb3VudHJ5PUNvdW50cnkuUmVnaW9uKQ0KICAjIyBjb252ZXJ0IGZyb20gd2lkZSB0byBsb25nIGZvcm1hdA0KICBkYXRhICU8PiUgZ2F0aGVyKGtleT1kYXRlLCB2YWx1ZT1jb3VudCwgLWNvdW50cnkpDQogICMjIGNvbnZlcnQgZnJvbSBjaGFyYWN0ZXIgdG8gZGF0ZQ0KICBkYXRhICU8PiUgbXV0YXRlKGRhdGUgPSBkYXRlICU+JSBtZHkoKSkNCiAgIyMgYWdncmVnYXRlIGJ5IGNvdW50cnkNCiAgZGF0YSAlPD4lIGdyb3VwX2J5KGNvdW50cnksIGRhdGUpICU+JSBzdW1tYXJpc2UoY291bnQ9c3VtKGNvdW50LCBuYS5ybT1UKSkgJT4lIGFzLmRhdGEuZnJhbWUoKQ0KICByZXR1cm4oZGF0YSkNCn0NCiMjIGNsZWFuIHRoZSB0aHJlZSBkYXRhIHNldHMNCmRhdGEuY29uZmlybWVkIDwtIGRmX2NvbmYgJT4lIGNsZWFuRGF0YSgpICU+JSByZW5hbWUoY29uZmlybWVkPWNvdW50KQ0KZGF0YS5kZWF0aHMgPC0gZGZfZGVhdGhzICU+JSBjbGVhbkRhdGEoKSAlPiUgcmVuYW1lKGRlYXRocz1jb3VudCkNCmRhdGEucmVjb3ZlcmVkIDwtIGRmX3JlY292ZXIgJT4lIGNsZWFuRGF0YSgpICU+JSByZW5hbWUocmVjb3ZlcmVkPWNvdW50KQ0KZGF0YSA8LSBkYXRhLmNvbmZpcm1lZCAlPiUgbWVyZ2UoZGF0YS5kZWF0aHMsIGFsbD1UKSAlPiUgbWVyZ2UoZGF0YS5yZWNvdmVyZWQsIGFsbD1UKQ0KZGF0YQ0KIyMgY291bnRyaWVzL3JlZ2lvbnMgd2l0aCBjb25maXJtZWQgY2FzZXMsIGV4Y2wuIGNydWlzZSBzaGlwcw0KY291bnRyaWVzIDwtIGRhdGEgJT4lIHB1bGwoY291bnRyeSkgJT4lIHNldGRpZmYoJ0NydWlzZSBTaGlwJykNCmRhdGENCg0KZGF0YS53b3JsZCA8LSBkYXRhICU+JSBncm91cF9ieShkYXRlKSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50cnk9J1dvcmxkJywNCiAgICAgICAgICAgIGNvbmZpcm1lZCA9IHN1bShjb25maXJtZWQsIG5hLnJtPVQpLA0KICAgICAgICAgICAgZGVhdGhzID0gc3VtKGRlYXRocywgbmEucm09VCksDQogICAgICAgICAgICByZWNvdmVyZWQgPSBzdW0ocmVjb3ZlcmVkLCBuYS5ybT1UKSkNCmRhdGEgJTw+JSByYmluZChkYXRhLndvcmxkKQ0KZGF0YQ0KZGF0YSAlPD4lIG11dGF0ZShjdXJyZW50LmNvbmZpcm1lZCA9IGNvbmZpcm1lZCAtIGRlYXRocyAtIHJlY292ZXJlZCkNClZpZXcoZGF0YSkNCg0KYGBgDQpgYGB7cn0NCnggPC0gcmF3LmNvbmZpcm1lZA0KeCRjb25maXJtZWQgPC0geFssIG5jb2woeCldDQp4ICU8PiUgc2VsZWN0KGMoQ291bnRyeS5SZWdpb24sIFByb3ZpbmNlLlN0YXRlLCBMYXQsIExvbmcsIGNvbmZpcm1lZCkpICU+JQ0KbXV0YXRlKHR4dD1wYXN0ZTAoQ291bnRyeS5SZWdpb24sICcgLSAnLCBQcm92aW5jZS5TdGF0ZSwgJzogJywgY29uZmlybWVkKSkNCm0gPC0gbGVhZmxldCh3aWR0aD0xMjAwLCBoZWlnaHQ9ODAwKSAlPiUgYWRkVGlsZXMoKQ0KIyBjaXJjbGUgbWFya2VyICh1bml0cyBpbiBwaXhlbHMpDQptICU8PiUgYWRkQ2lyY2xlTWFya2Vycyh4JExvbmcsIHgkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIyByYWRpdXM9Mitsb2cyKHgkY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cz0wLjAzKnNxcnQoeCRjb25maXJtZWQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgc3Ryb2tlPUYsDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj0ncmVkJywgZmlsbE9wYWNpdHk9MC4zLA0KICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9eCR0eHQpDQojIHdvcmxkDQptDQpgYGANCmBgYHtyfQ0KIyMgQ2hpbmENCm0gJT4lIHNldFZpZXcoOTUsIDM1LCB6b29tPTQpDQojIyBBdXN0cmFsaWEgYW5kIE5ldyBaZWFsYW5kDQptICU+JSBzZXRWaWV3KDEzNSwgLTI3LCB6b29tPTQpDQojIyBVUyBhbmQgQ2FuYWRhDQptICU+JSBzZXRWaWV3KC0xMDUsIDQwLCB6b29tPTQpDQojIyBFdXJvcGUNCm0gJT4lIHNldFZpZXcoMTAsIDUwLCB6b29tPTQpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI3JhdGUNCmRhdGEgJTw+JSBhcnJhbmdlKGNvdW50cnksIGRhdGUpDQpuIDwtIG5yb3coZGF0YSkNCmRheTEgPC0gbWluKGRhdGEkZGF0ZSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBkZWF0aHMgLSBsYWcoZGVhdGhzLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LnJlY292ZXJlZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCByZWNvdmVyZWQgLSBsYWcocmVjb3ZlcmVkLCBuPTEpKSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKG5ldy5yZWNvdmVyZWQgPCAwLCAwLCBuZXcucmVjb3ZlcmVkKSkNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgZGVhdGhzIGFuZCByZWNvdmVyZWQgY2FzZXMNCmRhdGEgJTw+JSBtdXRhdGUocmF0ZS51cHBlciA9ICgxMDAgKiBkZWF0aHMgLyAoZGVhdGhzICsgcmVjb3ZlcmVkKSkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLnVwcGVyID0gaWZlbHNlKGlzLm5hbihyYXRlLnVwcGVyKSwgMCwgcmF0ZS51cHBlcikpDQoNCiMjIGxvd2VyIGJvdW5kOiBkZWF0aCByYXRlIGJhc2VkIG9uIHRvdGFsIGNvbmZpcm1lZCBjYXNlcw0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmxvd2VyID0gKDEwMCAqIGRlYXRocyAvIGNvbmZpcm1lZCkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLmxvd2VyID0gaWZlbHNlKGlzLm5hbihyYXRlLmxvd2VyKSwgMCwgcmF0ZS5sb3dlcikpDQoNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdGhlIG51bWJlciBvZiBkZWF0aC9yZWNvdmVyZWQgb24gZXZlcnkgc2luZ2xlIGRheQ0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmRhaWx5ID0gKDEwMCAqIG5ldy5kZWF0aHMgLyAobmV3LmRlYXRocyArIG5ldy5yZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUuZGFpbHkgPSBpZmVsc2UoaXMubmFuKHJhdGUuZGFpbHkpLCAwLCByYXRlLmRhaWx5KSkNCg0KVmlldyhkYXRhKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQNCmRhdGEubG9uZyA8LSBkYXRhICU+JQ0KICBzZWxlY3QoYyhjb3VudHJ5LCBkYXRlLCBjb25maXJtZWQsIGN1cnJlbnQuY29uZmlybWVkLCByZWNvdmVyZWQsIGRlYXRocykpICU+JQ0KICBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtYyhjb3VudHJ5LCBkYXRlKSkNCiMjIHNldCBmYWN0b3IgbGV2ZWxzIHRvIHNob3cgdGhlbSBpbiBhIGRlc2lyYWJsZSBvcmRlcg0KZGF0YS5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLCBjb25maXJtZWQ9J1RvdGFsIENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY292ZXJlZD0nUmVjb3ZlcmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGhzPSdEZWF0aHMnKSkNClZpZXcoZGF0YS5sb25nKQ0KYGBgDQoNCmBgYHtyfQ0KIyNOdW1iZXIgb2YgY2FzZSBXb3JsZA0Kd29ybGQgPC0gZmlsdGVyKGRhdGEubG9uZyxjb3VudHJ5ID09ICdXb3JsZCcpDQpwbG90MSA8LSB3b3JsZCAlPiUgZmlsdGVyKHR5cGUgIT0gJ1RvdGFsIENvbmZpcm1lZCcpICU+JQ0KICBnZ3Bsb3QoYWVzKHg9ZGF0ZSwgeT1jb3VudCkpICsNCiAgZ2VvbV9hcmVhKGFlcyhmaWxsPXR5cGUpLCBhbHBoYT0wLjUpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ051bWJlcnMgb2YgQ2FzZXMgV29ybGR3aWRlIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygncmVkJywgJ2dyZWVuJywgJ2JsYWNrJykpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPSdib3R0b20nLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NyksDQogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZT11bml0KDAuMiwgJ2NtJyksDQogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTYpLA0KICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NyksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90MiA8LSB3b3JsZCAlPiUNCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9Y291bnQpKSArDQogIGdlb21fbGluZShhZXMoY29sb3I9dHlwZSkpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ051bWJlcnMgb2YgQ2FzZXMgV29ybGR3aWRlIChsb2cgc2NhbGUpIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoJ3B1cnBsZScsICdyZWQnLCAnZ3JlZW4nLCAnYmxhY2snKSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLCBsZWdlbmQucG9zaXRpb249J2JvdHRvbScsDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT03KSwNCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLmtleS5zaXplPXVuaXQoMC4yLCAnY20nKSwNCiAgICAgICAgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NiksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT03KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykNCiMjIHNob3cgdHdvIHBsb3RzIHNpZGUgYnkgc2lkZQ0KZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgbmNvbD0yKQ0KDQpnbHkucGxvdDIgPC0gZ2dwbG90bHkocGxvdDIpDQpnbHkucGxvdDINCmBgYA0KDQpgYGB7cn0NCiMjIEN1cnJlbnQgQ29uZmlybWVkIENhc2VzDQpkYXRhLndvcmxkIDwtIGRhdGEgJT4lIGZpbHRlcihjb3VudHJ5PT0nV29ybGQnKQ0KbiA8LSBucm93KGRhdGEud29ybGQpDQpwbG90MSA8LSBnZ3Bsb3QoZGF0YS53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1jdXJyZW50LmNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0N1cnJlbnQgQ29uZmlybWVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdDIgPC0gZ2dwbG90KGRhdGEud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LmNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0RhaWx5IE5ldyBDb25maXJtZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQojIyBzaG93IHR3byBwbG90cyBzaWRlIGJ5IHNpZGUNCmdyaWQuYXJyYW5nZShwbG90MSwgcGxvdDIsIG5jb2w9MikNCmBgYA0KYGBge3J9DQojIyBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgc21vb3RoZWQgbGluZSBhbmQgdmVydGljYWwgeC1heGlzIGxhYmVscw0KcGxvdDEgPC0gZ2dwbG90KGRhdGEud29ybGQsIGFlcyh4PWRhdGUsIHk9ZGVhdGhzKSkgKw0KICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpICsNCiAgeGxhYignJykgKyB5bGFiKCdDb3VudCcpICsgbGFicyh0aXRsZT0nQWNjdW11bGF0aXZlIERlYXRocycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCnBsb3QyIDwtIGdncGxvdChkYXRhLndvcmxkLCBhZXMoeD1kYXRlLCB5PXJlY292ZXJlZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0FjY3VtdWxhdGl2ZSBSZWNvdmVyZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90MyA8LSBnZ3Bsb3QoZGF0YS53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1uZXcuZGVhdGhzKSkgKw0KICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpICsNCiAgeGxhYignJykgKyB5bGFiKCdDb3VudCcpICsgbGFicyh0aXRsZT0nTmV3IERlYXRocycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCnBsb3Q0IDwtIGdncGxvdChkYXRhLndvcmxkLCBhZXMoeD1kYXRlLCB5PW5ldy5yZWNvdmVyZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdOZXcgUmVjb3ZlcmVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KIyMgc2hvdyBmb3VyIHBsb3RzIHRvZ2V0aGVyLCB3aXRoIDIgcGxvdHMgaW4gZWFjaCByb3cNCmdyaWQuYXJyYW5nZShwbG90MSwgcGxvdDIsIHBsb3QzLCBwbG90NCwgbnJvdz0yKQ0KDQpgYGANCg0KYGBge3J9DQojIyBjb252ZXJ0IGZyb20gd2lkZSB0byBsb25nIGZvcm1hdCwgZm9yIGRyYXdpbmcgYXJlYSBwbG90cw0KcmF0ZXMubG9uZyA8LSBkYXRhICU+JQ0KICBzZWxlY3QoYyhjb3VudHJ5LCBkYXRlLCByYXRlLnVwcGVyLCByYXRlLmxvd2VyLCByYXRlLmRhaWx5KSkgJT4lDQogIGdhdGhlcihrZXk9dHlwZSwgdmFsdWU9Y291bnQsIC1jKGNvdW50cnksIGRhdGUpKQ0KIyBzZXQgZmFjdG9yIGxldmVscyB0byBzaG93IHRoZW0gaW4gYSBkZXNpcmFibGUgb3JkZXINCnJhdGVzLmxvbmcgJTw+JSBtdXRhdGUodHlwZT1yZWNvZGVfZmFjdG9yKHR5cGUsIHJhdGUuZGFpbHk9J0RhaWx5JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmF0ZS51cHBlcj0nVXBwZXIgYm91bmQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYXRlLmxvd2VyID0gJ0xvd2VyIGJvdW5kJykpIA0KI1ZpZXcocmF0ZXMubG9uZykgDQoNCmcgPC0gcmF0ZXMubG9uZyAlPiUgZmlsdGVyKGNvdW50cnkgPT0gIldvcmxkIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gY291bnQsIGNvbG9yID0gdHlwZSkpICsgDQogIGdlb21fbGluZSgpICsNCiAgeGxhYigiIikgKyB5bGFiKCJEZWF0aCBSYXRlICglKSIpDQoNCmcNCg0KZ2x5LmRlYXRoIDwtIGdncGxvdGx5KGcpDQpnbHkuZGVhdGgNCmBgYA0KDQpgYGB7cn0NCiMjIHJhbmtpbmcgYnkgY29uZmlybWVkIGNhc2VzDQpkYXRhLmxhdGVzdC5hbGwgPC0gZGF0YSAlPiUgZmlsdGVyKGRhdGUgPT0gbWF4KGRhdGUpKSAlPiUNCiAgc2VsZWN0KGNvdW50cnksIGRhdGUsY29uZmlybWVkLCBuZXcuY29uZmlybWVkLCBjdXJyZW50LmNvbmZpcm1lZCwNCiAgICAgICAgIHJlY292ZXJlZCwgZGVhdGhzLCBuZXcuZGVhdGhzLCBkZWF0aC5yYXRlPXJhdGUubG93ZXIpICU+JQ0KICBtdXRhdGUocmFua2luZyA9IGRlbnNlX3JhbmsoZGVzYyhjb25maXJtZWQpKSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNClZpZXcoZGF0YS5sYXRlc3QuYWxsKQ0KDQprIDwtIDIwDQojIyB0b3AgMjAgY291bnRyaWVzOiAyMSBpbmNsLiAnV29ybGQnDQp0b3AuY291bnRyaWVzIDwtIGRhdGEubGF0ZXN0LmFsbCAlPiUgZmlsdGVyKHJhbmtpbmcgPD0gayArIDEpICU+JQ0KICBhcnJhbmdlKHJhbmtpbmcpICU+JSBwdWxsKGNvdW50cnkpICU+JSBhcy5jaGFyYWN0ZXIoKQ0KdG9wLmNvdW50cmllcyAlPiUgc2V0ZGlmZignV29ybGQnKSAlPiUgcHJpbnQoKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YS5sYXRlc3QgPC0gZGF0YS5sYXRlc3QuYWxsICU+JSBmaWx0ZXIoIWlzLm5hKGNvdW50cnkpKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9aWZlbHNlKHJhbmtpbmcgPD0gayArIDEsIGFzLmNoYXJhY3Rlcihjb3VudHJ5KSwgJ090aGVycycpKSAlPiUNCiAgbXV0YXRlKGNvdW50cnk9Y291bnRyeSAlPiUgZmFjdG9yKGxldmVscz1jKHRvcC5jb3VudHJpZXMsICdPdGhlcnMnKSkpDQpkYXRhLmxhdGVzdCAlPD4lIGdyb3VwX2J5KGNvdW50cnkpICU+JQ0KICBzdW1tYXJpc2UoY29uZmlybWVkPXN1bShjb25maXJtZWQpLCBuZXcuY29uZmlybWVkPXN1bShuZXcuY29uZmlybWVkKSwNCiAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPXN1bShjdXJyZW50LmNvbmZpcm1lZCksDQogICAgICAgICAgICByZWNvdmVyZWQ9c3VtKHJlY292ZXJlZCksIGRlYXRocz1zdW0oZGVhdGhzKSwgbmV3LmRlYXRocz1zdW0obmV3LmRlYXRocykpICU+JQ0KICBtdXRhdGUoZGVhdGgucmF0ZT0oMTAwICogZGVhdGhzL2NvbmZpcm1lZCkgJT4lIHJvdW5kKDEpKSANCmRhdGEubGF0ZXN0DQpkYXRhLmxhdGVzdCAlPD4lIHNlbGVjdChjKGNvdW50cnksIGNvbmZpcm1lZCwgZGVhdGhzLCBkZWF0aC5yYXRlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcuY29uZmlybWVkLCBuZXcuZGVhdGhzLCBjdXJyZW50LmNvbmZpcm1lZCxyZWNvdmVyZWQpKSAlPiUNCiAgbXV0YXRlKHJlY292ZXIucmF0ZT0oMTAwICogcmVjb3ZlcmVkL2NvbmZpcm1lZCkgJT4lIHJvdW5kKDEpKQ0KZGF0YS5sYXRlc3QNCg0KZGZfcG9wIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIHBvcHVsYXRpb24gIikpDQpkZl9wb3AgPC0gYXMuZGF0YS5mcmFtZShkZl9wb3ApDQpkZl9wb3AgPC0gcmVuYW1lKGRmX3BvcCwiY291bnRyeSI9IkNvdW50cnkiKQ0KDQojIEFkZCBXb3JsZCBQb3B1bGF0aW9uDQp3b3JsZF9wb3AgPC0gc3VtKGRmX3BvcCRgUG9wdWxhdGlvbiAoMjAyMClgKQ0KZGZfcG9wW25yb3coZGZfcG9wKSArIDEsXSA9IGMoIldvcmxkIiwgd29ybGRfcG9wKQ0KDQojIEFkZCBPdGhlciBDb3VudHJpZXMgUG9wdWxhdGlvbg0KdG9wX3BvcCA8LSBmaWx0ZXIoZGZfcG9wLCBkZl9wb3AkY291bnRyeSAlaW4lIHRvcC5jb3VudHJpZXMgJiBkZl9wb3AkY291bnRyeSAhPSAiV29ybGQiKQ0KdG9wX3BvcCA8LSBzdW0odG9wX3BvcCRgUG9wdWxhdGlvbiAoMjAyMClgICU+JSBhcy5udW1lcmljKCkpDQpvdGhlcnNfcG9wIDwtICh3b3JsZF9wb3AgLSB0b3BfcG9wKSANCmRmX3BvcFtucm93KGRmX3BvcCkgKyAxLF0gPSBjKCJPdGhlcnMiLCBvdGhlcnNfcG9wKQ0KI1ZpZXcoZGZfcG9wKQ0KDQpkYXRhLmxhdGVzdCA8LSBtZXJnZSh4ID0gZGF0YS5sYXRlc3QsIHkgPSBkZl9wb3AsIGJ5ID0gImNvdW50cnkiLCBhbGwueCA9IFRSVUUpIA0KZGF0YS5sYXRlc3QNCmRhdGEubGF0ZXN0IDwtIHJlbmFtZShkYXRhLmxhdGVzdCwicG9wdWxhdGlvbiIgPSAiUG9wdWxhdGlvbiAoMjAyMCkiKQ0KZGF0YS5sYXRlc3QkcG9wdWxhdGlvbiA8LSBkYXRhLmxhdGVzdCRwb3B1bGF0aW9uICU+JSBhcy5udW1lcmljKCkNCmRhdGEubGF0ZXN0ICA8LSBkYXRhLmxhdGVzdCAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgY29uZmlybWVkLCBkZWF0aHMsIGRlYXRoLnJhdGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5jb25maXJtZWQsIG5ldy5kZWF0aHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkLCByZWNvdmVyZWQsIHJlY292ZXIucmF0ZSwgcG9wdWxhdGlvbikpICU+JQ0KICBtdXRhdGUoY29uZmlybS5yYXRlID0gKDEwMCAqIGNvbmZpcm1lZCAvIHBvcHVsYXRpb24pICU+JSByb3VuZCgxKSkNCmRhdGEubGF0ZXN0DQpgYGANCmBgYHtyfQ0KZGF0YS5sYXRlc3QgJT4lIG11dGF0ZShkZWF0aC5yYXRlPWRlYXRoLnJhdGUgJT4lIGZvcm1hdChuc21hbGw9MSkgJT4lIHBhc3RlMCgnJScpKQ0KDQpgYGANCg0KYGBge3J9DQojIyBjb252ZXJ0IGZyb20gd2lkZSB0byBsb25nIGZvcm1hdCwgZm9yIGRyYXdpbmcgYXJlYSBwbG90cw0KZGF0YS5sYXRlc3QubG9uZyA8LSBkYXRhLmxhdGVzdCAlPiUgZmlsdGVyKGNvdW50cnkhPSdXb3JsZCcpICU+JQ0KICBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtY291bnRyeSkNCiMjIHNldCBmYWN0b3IgbGV2ZWxzIHRvIHNob3cgdGhlbSB3aXRoIHByb3BlciB0ZXh0IGFuZCBpbiBhIGRlc2lyYWJsZSBvcmRlcg0KZGF0YS5sYXRlc3QubG9uZyAlPD4lIG11dGF0ZSh0eXBlPXJlY29kZV9mYWN0b3IodHlwZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm1lZD0nVG90YWwgQ29uZmlybWVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRocz0nVG90YWwgRGVhdGhzJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlYXRoLnJhdGU9J0RlYXRoIFJhdGUgKCUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5jb25maXJtZWQ9J05ldyBDb25maXJtZWQgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5kZWF0aHM9J05ldyBEZWF0aHMgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWNvdmVyLnJhdGUgPSAnUmVjb3ZlciBSYXRlKCUpJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpcm0ucmF0ZSA9ICdDb25maXJtZWQgUmF0ZSglKScpKQ0KI1ZpZXcoZGF0YS5sYXRlc3QubG9uZykNCmRhdGEub25lLmRlbSA8LSBmaWx0ZXIoZGF0YS5sYXRlc3QubG9uZyx0eXBlPT0nVG90YWwgQ29uZmlybWVkJw0KICAgICAgICAgICAgICAgICAgICAgICB8IHR5cGU9PSdUb3RhbCBEZWF0aHMnDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J0N1cnJlbnQgQ29uZmlybWVkJykNCmRhdGEudHdvLmRlbSA8LSBmaWx0ZXIoZGF0YS5sYXRlc3QubG9uZyx0eXBlPT0nRGVhdGggUmF0ZSAoJSknDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J05ldyBDb25maXJtZWQgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJw0KICAgICAgICAgICAgICAgICAgICAgICB8IHR5cGU9PSdOZXcgRGVhdGhzIChjb21wYXJlZCB3aXRoIG9uZSBkYXkgYmVmb3JlKScNCiAgICAgICAgICAgICAgICAgICAgICAgfCB0eXBlPT0nUmVjb3ZlciBSYXRlKCUpJw0KICAgICAgICAgICAgICAgICAgICAgICB8IHR5cGU9PSdDb25maXJtZWQgUmF0ZSglKScpDQpkYXRhLnR3by5kZW0NCmBgYA0KDQpgYGB7cn0NCiMjIGJhciBjaGFydA0KZGF0YS5vbmUuZGVtICU+JSBnZ3Bsb3QoYWVzKHg9Y291bnRyeSwgeT1jb3VudCwgZmlsbD1jb3VudHJ5LCBncm91cD1jb3VudHJ5KSkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1jb3VudCwgeT1jb3VudCksIHNpemU9Mywgdmp1c3Q9MCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJycpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ1RvcCAyMCBDb3VudHJpZXMgd2l0aCBNb3N0IENvbmZpcm1lZCBDYXNlcyAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSdDb3VudHJ5JywgbGFiZWxzPWFlcyhjb3VudCkpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkgKw0KICBmYWNldF93cmFwKH50eXBlLCBuY29sPTEsIHNjYWxlcz0nZnJlZV95JykNCg0KYGBgDQpgYGB7cn0NCg0KZGF0YS50d28uZGVtICU+JSBnZ3Bsb3QoYWVzKHg9Y291bnRyeSwgeT1jb3VudCwgZmlsbD1jb3VudHJ5LCBncm91cD1jb3VudHJ5KSkgKw0KICBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1jb3VudCwgeT1jb3VudCksIHNpemU9Mywgdmp1c3Q9MCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJycpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoJ1RvcCAyMCBDb3VudHJpZXMgd2l0aCBNb3N0IENvbmZpcm1lZCBDYXNlcyAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfZmlsbF9kaXNjcmV0ZShuYW1lPSdDb3VudHJ5JywgbGFiZWxzPWFlcyhjb3VudCkpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMyksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkgKw0KICBmYWNldF93cmFwKH50eXBlLCBuY29sPTEsIHNjYWxlcz0nZnJlZV95JykNCmBgYA0KDQpgYGB7cn0NCiMjR0RQDQpkZl9nZHAgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gZ2RwIikpDQpkZl9nZHAgPC0gYXMuZGF0YS5mcmFtZShkZl9nZHApDQpkZl9nZHAgPC0gcmVuYW1lKGRmX2dkcCwiY291bnRyeSI9IlJlYWwgR0RQIGdyb3d0aCAoQW5udWFsIHBlcmNlbnQgY2hhbmdlKSIpDQpkZl9nZHAgPC0gc2VsZWN0KGRmX2dkcCxjKCJjb3VudHJ5IiwiMjAxMiIsIjIwMTMiLCIyMDE0IiwiMjAxNSIsIjIwMTYiLCIyMDE3IiwiMjAxOCIsIjIwMTkiLCIyMDIwIiwiMjAyMSIpKQ0KZGZfZ2RwDQpkZl9nZHAyMDE5IDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGdkcDE5IikpDQpkZl9nZHAyMDE5IDwtIGFzLmRhdGEuZnJhbWUoZGZfZ2RwMjAxOSkNCmRmX2dkcDIwMTkNCg0KYGBgDQpgYGB7cn0NCiNoZWFsdGhyYW5raW5nDQpkZl9oZWFsdCA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBoZWFsdGhyYW5raW5nIikpDQpkZl9oZWFsdCA8LSBhcy5kYXRhLmZyYW1lKGRmX2hlYWx0KQ0KZGZfaGVhbHQgPC0gc2VsZWN0KGRmX2hlYWx0LGMoImNvdW50cnkiLCJoZWFsdGhDYXJlSW5kZXgiKSkNClZpZXcoZGZfaGVhbHQpDQpgYGANCg0KYGBge3J9DQojVG9wMjBQb3JuaHViDQpkZl9wb3JuaHViIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIFBvcm5odWIiKSkNCmRmX3Bvcm5odWIgPC0gYXMuZGF0YS5mcmFtZShkZl9wb3JuaHViKQ0KZGZfcG9ybmh1Yg0KYGBgDQoNCmBgYHtyfQ0KI3RlbXANCmRmX3RlbXAgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gd29ybGRfdGVtcCIpKQ0KZGZfdGVtcCA8LSBhcy5kYXRhLmZyYW1lKGRmX3RlbXApIA0KZGZfdGVtcCRDb3VudHJ5W2RmX3RlbXAkQ291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyJdIDwtICJVUyINCg0KZGZfY2l0eSA8LSBzZWxlY3QoZGZfdGVtcCxjKCJDb3VudHJ5IiwiQ2l0eSIpKSAlPiUNCiAgcmVuYW1lKGNvdW50cnk9Q291bnRyeSkgJT4lIA0KICByZW5hbWUoY2l0eT1DaXR5KQ0KDQpudW1vZmNpdHkgPC0gYWdncmVnYXRlKGNpdHkgfiBjb3VudHJ5LCBkYXRhID0gZGZfY2l0eSwgbGVuZ3RoKQ0KDQpkZl90ZW1wIDwtIHNlbGVjdChkZl90ZW1wLGMoIkNvdW50cnkiLCJBdmdfWWVhciIpKSAlPiUNCiAgcmVuYW1lKGNvdW50cnk9Q291bnRyeSkNClZpZXcoZGZfdGVtcCkNCg0KI2RmX3RlbXAgPC0gZGF0YS5mcmFtZShjb3VudHJ5PWRmX3RlbXBbLDFdLGF2Zz1yb3dNZWFucyhkZl90ZW1wWywtMV0pKQ0KZGZfdGVtcCA8LSBkZl90ZW1wICU8PiUgZ3JvdXBfYnkoY291bnRyeSkgJT4lIHN1bW1hcmlzZShhdmdfdGVtcCA9IG1lYW4oQXZnX1llYXIsbmEucm0gPSBUUlVFKSU+JSByb3VuZCgxKSkNCmRmX3RlbXANCmBgYA0KDQpgYGB7cn0NCiNkaXNwbGF5LmJyZXdlci5hbGwoKQ0KZGZfdGVtcC5hbGwgPC0gZGZfdGVtcCAlPiUgbWVyZ2UoZGF0YS5sYXRlc3QuYWxsKQ0KVmlldyhkZl90ZW1wLmFsbCkNCmRmX3RlbXBfdG9wLmFsbCA8LSBkZl90ZW1wLmFsbCAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNClZpZXcoZGZfdGVtcF90b3ApDQpnX3RlbXBfdG9wIDwtIGRmX3RlbXBfdG9wICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHJhbmtpbmcpLCB5ID0gYXZnX3RlbXAsIGZpbGwgPSBhdmdfdGVtcCkpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoIlRlbXBlcmF0dXJlIGluIFRvcCAgMjAgY291bnRyaWVzIiksIHN1YnRpdGxlID0gIkF2ZXJhZ2UgVGVtcGVyYXR1cmUgaW4gVG9wIDIwIGNvdW50cmllcyB3aXRoIG1vc3QgY29uZmlybWVkIGNhc2VzICjCsEMpICgyMDIwKSIpICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIiM5M0RCRkYiLCBoaWdoID0gIiNGRjc3NzEiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9YXZnX3RlbXAsIHk9YXZnX3RlbXApLCBzaXplPTQsIHZqdXN0PS0wLjUpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICB0aGVtZSgNCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemUgPSA5LCBhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0gIkNvdW50cnkiKSArDQogIHNjYWxlX3lfZGlzY3JldGUobmFtZSA9ICJBdmVyYWdlIFRlbXBlcmF0dXJlIikNCg0KICAgICAgICAgICAjbGFicyh0aXRsZSA9ICJUZW1wZXJhdHVyZSBpbiBUb3AgIDIwIGNvdW50cmllcyIsIHN1YnRpdGxlID0gIlRlbXBlcmF0dXJlIGluIFRvcCAyMCBjb3VudHJpZXMgd2l0aCBtb3N0IGNvbmZpcm1lZCBjYXNlcyAowrBDKSIpDQogICAgICAgICANCiNnX3RlbXBfdG9wICAgICAgICAgDQpnX3RlbXBfdG9wIA0KYGBgDQoNCg0KYGBge3J9DQojZGZfY29uZg0KI2RhdGEubGF0ZXN0LmFsbA0KbGF0LmxvbmcgPC0gcmVuYW1lKGRmX2NvbmYsICJjb3VudHJ5IiA9ICJDb3VudHJ5LlJlZ2lvbiIsICJjaXR5IiA9ICJQcm92aW5jZS5TdGF0ZSIpICU+JSANCiAgc2VsZWN0KCJjb3VudHJ5IiwgIkxhdCIsICJMb25nIikgJT4lIA0KICBtZXJnZShkZl90ZW1wLmFsbFtjKCJjb3VudHJ5IiwiY29uZmlybWVkIiwgInJlY292ZXJlZCIsICJkZWF0aHMiLCAiYXZnX3RlbXAiLCAicmFua2luZyIpXSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBkaXN0aW5jdChjb3VudHJ5LCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNClZpZXcobGF0LmxvbmcpDQpgYGANCg0KYGBge3J9DQpsYWJlbF93b3JsZCA8LSBsYXQubG9uZyANCmxhYmVsX3dvcmxkJGF2Z190ZW1wIDwtIGFzLm51bWVyaWMobGFiZWxfd29ybGRbLCBuYW1lcyhsYWJlbF93b3JsZCkgJWluJSBjKCJhdmdfdGVtcCIpXSkNCmxhYmVsX3dvcmxkIDwtIGxhYmVsX3dvcmxkICU+JSAgDQogIG11dGF0ZSh0eHQ9cGFzdGUwKCc8Yj4nLHJhbmtpbmcsICc8L2I+JywNCiAgICAgICAgICAgICAgICAgICAgJzxici8+JywnPGI+Jyxjb3VudHJ5LCAnPC9iPicsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJUZW1wZXJhdHVyZTogICIsYXZnX3RlbXAsICcgwrBDJywNCiAgICAgICAgICAgICAgICAgICAgJzxici8+JywgIkNvbmZpcm1lZDogICIsIGNvbmZpcm1lZCwgDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJEZWF0aHM6ICIsIGRlYXRocywNCiAgICAgICAgICAgICAgICAgICAgJzxici8+JywgIlJlY292ZXJlZDogIiwgcmVjb3ZlcmVkDQogICAgICAgICAgICAgICAgICAgICkpIA0KDQpsYWJlbF93b3JsZCR0eHQgPC0gbGFiZWxfd29ybGQkdHh0ICU+JSBsYXBwbHkoaHRtbHRvb2xzOjpIVE1MKQ0KbGFiZWxfd29ybGQgDQoNCmxhYmVsX3RvcCA8LSBsYWJlbF93b3JsZCAlPiUgZmlsdGVyKHJhbmtpbmcgPCAyMSkNCmxhYmVsX3RvcA0KYGBgDQoNCmBgYHtyfQ0Kd3BhbCA8LSBjb2xvck51bWVyaWMoIllsT3JSZCIsIGxhYmVsX3dvcmxkJGF2Z190ZW1wLCBuID0gNCkNCg0KdG9wSWNvbiA8LSBtYWtlSWNvbigic3Rhci5wbmciLA0KICAjaWNvblVybCA9ICJodHRwczovL3N0YXRpYy52ZWN0ZWV6eS5jb20vc3lzdGVtL3Jlc291cmNlcy9wcmV2aWV3cy8wMDEvMTg5LzA2My9ub25fMngvc3Rhci1yb3VuZGVkLXBuZy5wbmciLA0KICBpY29uV2lkdGggPSAxMCwgaWNvbkhlaWdodCA9IDEwDQogICNpY29uQW5jaG9yWCA9IDIwLCBpY29uQW5jaG9yWSA9IDIwDQogIA0KKQ0KDQpsYWJlbF93b3JsZCA8LSBsYWJlbF93b3JsZCAlPiUgZmlsdGVyKHJhbmtpbmcgPiAyMCkgDQogIA0KbSA8LSBsZWFmbGV0KHdpZHRoPTEyMDAsIGhlaWdodD04MDApICU+JSBhZGRUaWxlcygpICANCm0gJTw+JSAgYWRkQ2lyY2xlTWFya2VycyhsYWJlbF93b3JsZCRMb25nLCBsYWJlbF93b3JsZCRMYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAjIHJhZGl1cz0yK2xvZzIoeCRjb25maXJtZWQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgcmFkaXVzPTEwLCMqbG9nMihtLndvcmxkJGF2Zy50ZW1wKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0cm9rZT1GLA0KICAgICAgICAgICAgICAgICAgICAgICAgI2NvbG9yPSdyZWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB3cGFsKGxhYmVsX3dvcmxkJGF2Z190ZW1wKSwgDQogICAgICAgICAgICAgICAgICAgICAgICBmaWxsT3BhY2l0eT0wLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAjcG9wdXA9bGFiZWwudG9wJHR4dA0KICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWw9IGxhYmVsX3dvcmxkJHR4dCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gIldvcmxkIg0KICAgICAgICAgICAgICAgICAgICAgICAgKSAlPiUNCiAgDQogIGFkZENpcmNsZU1hcmtlcnMobGFiZWxfdG9wJExvbmcsIGxhYmVsX3RvcCRMYXQsDQogICAgICAgICAgICAgICAgICAgICAgICAjIHJhZGl1cz0yK2xvZzIoeCRjb25maXJtZWQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgcmFkaXVzPTEwLCMqbG9nMihtLndvcmxkJGF2Zy50ZW1wKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0cm9rZT1GLA0KICAgICAgICAgICAgICAgICAgICAgICAgI2NvbG9yPSdyZWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB3cGFsKGxhYmVsX3RvcCRhdmdfdGVtcCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHk9MC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgI3BvcHVwPWxhYmVsLnRvcCR0eHQNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSBsYWJlbF90b3AkdHh0LA0KICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSAiVG9wIDIwIENvdW50cmllcyINCiAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lDQogIA0KICBhZGRMYWJlbE9ubHlNYXJrZXJzKGxhYmVsX3RvcCRMb25nLCBsYWJlbF90b3AkTGF0LCBsYWJlbCA9IGxhYmVsX3RvcCRyYW5raW5nLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVsT3B0aW9ucyA9IGxhYmVsT3B0aW9ucyhub0hpZGUgPSBUUlVFLCB0ZXh0T25seSA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiaGVhZCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQgPSBjKDUsNCkpLA0KICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gIlRvcCAyMCBDb3VudHJpZXMiKSAlPiUNCiAgDQogIGFkZExlZ2VuZCgiYm90dG9tcmlnaHQiLCBwYWwgPSB3cGFsLCB2YWx1ZXMgPSBsYWJlbF93b3JsZCRhdmdfdGVtcCwgb3BhY2l0eSA9IDEsDQogICAgICAgICAgICBsYWJGb3JtYXQgPSBsYWJlbEZvcm1hdChzdWZmaXggPSAiIMKwQyIpLA0KICAgICAgICAgICAgdGl0bGUgPSAiVGVtcGVyYXR1cmUiKSAlPiUgDQogIA0KICBhZGRMYXllcnNDb250cm9sKA0KICAgICNiYXNlR3JvdXBzID0gYygiT1NNIChkZWZhdWx0KSIsICJUb25lciIsICJUb25lciBMaXRlIiksDQogICAgb3ZlcmxheUdyb3VwcyA9IGMoIlRvcCAyMCBDb3VudHJpZXMiLCAiV29ybGQiKSwNCiAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpDQogICkNCm0NCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KI1RvcCAyMCB3aXRoIGdkcA0KZGF0YS5sb25nR0RQIDwtIGRmX2dkcCAlPiUgZ2F0aGVyKGtleT15ZWFyLCB2YWx1ZT1HRFAsIC1jKGNvdW50cnkpKQ0KZGF0YS50b3AgPC0gZGF0YS5sYXRlc3QgJT4lIGZpbHRlcihjb3VudHJ5IT0nV29ybGQnJiBjb3VudHJ5IT0nT3RoZXJzJykNCiNkYXRhLnRvcCA8LSBoZWFkKGRhdGEudG9wLDIwKQ0KVmlldyhkYXRhLnRvcCkNCmRhdGEuZ2RwIDwtIGZpbHRlcihkYXRhLmxvbmdHRFAseWVhcj09JzIwMjAnKQ0KVmlldyhkYXRhLmdkcCkNCmBgYA0KDQpgYGB7cn0NCiNyYW5rIEdEUA0KZGF0YS50b3AuaGlnaHQgPC0gZGF0YS5nZHAgJT4lIHNlbGVjdChjb3VudHJ5LCB5ZWFyLEdEUCkgJT4lDQogIG11dGF0ZShyYW5raW5nID0gZGVuc2VfcmFuayhkZXNjKEdEUCkpKQ0KI2RhdGEudG9wLmhpZ2h0DQoNCmsgPC0gMjANCg0KdG9wLmdkcCA8LSBkYXRhLnRvcC5oaWdodCAlPiUgDQogIGZpbHRlcihyYW5raW5nIDwgaykgJT4lIA0KICBhcnJhbmdlKHJhbmtpbmcpDQoNCg0KZGF0YS50b3AubG93IDwtIGRhdGEuZ2RwICU+JSBzZWxlY3QoY291bnRyeSwgeWVhcixHRFApICU+JQ0KICBtdXRhdGUocmFua2luZyA9IGRlbnNlX3JhbmsoR0RQKSkNCmxvdy5nZHAubG9uZyA8LSBkYXRhLnRvcC5sb3cgJT4lIA0KICBmaWx0ZXIocmFua2luZyA8IGspICU+JSANCiAgYXJyYW5nZShyYW5raW5nKQ0KVmlldyhsb3cuZ2RwLmxvbmcpDQoNCg0KdG9wLmdkcA0KbG93LmdkcA0KYGBgDQoNCmBgYHtyfQ0KDQp3b3JsZC5nZHAgPC0gZGZfZ2RwICU+JSBmaWx0ZXIoY291bnRyeSA9PSAiV29ybGQiKSAlPiUNCiAgZ2F0aGVyKGtleSA9IFllYXIsIHZhbHVlID0gR0RQLCAtY291bnRyeSkNCndvcmxkLmdkcA0KDQp3b3JsZC5nZHAkZ3JvdXAgPC0gY3V0KHdvcmxkLmdkcCRHRFAsIGMoLUluZiwwLCBJbmYpLCBsYWJlbHMgPSBjKCItIiwiKyIpKQ0KDQpnIDwtIGdncGxvdCh3b3JsZC5nZHAsIGFlcyh4ID0gWWVhciwgeSA9IEdEUCwgZmlsbCA9IGdyb3VwKSkgKw0KICAgIGdlb21fdGV4dChhZXMobGFiZWw9R0RQLCB5ID0gR0RQKSwgc2l6ZT0zLCB2anVzdD0tMSkgKw0KICAgIGxhYnModGl0bGU9cGFzdGUwKCJSZWFsIEdEUCBncm93dGggKEFubnVhbCBwZXJjZW50IGNoYW5nZSkgb2YgV29ybGQgZnJvbSAyMDEyLTIwMjEiKSkrDQogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpKw0KICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIi0iID0gInJlZCIsIisiID0gImxpbWVncmVlbiIpKSsNCiAgICB0aGVtZV9idygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsNCiAgICB4bGFiKCIiKSsNCiAgICB0aGVtZSgjbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NyksDQogICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpKQ0KDQpnDQoNCmdseS53b3JsZC5nZHAgPC0gZ2dwbG90bHkoZykNCmdseS53b3JsZC5nZHANCmBgYA0KYGBge3J9DQpnZHAudG9wMjAgPC0gZGZfZ2RwMjAxOSAlPiUNCiAgc2VsZWN0KGMoInJhbmsiLCAiY291bnRyeSIsICJHRFAgKG1pbGxpb25zIG9mIFVTIGRvbGxhcnMpIikpICU+JQ0KICBtZXJnZShkYXRhLmxhdGVzdC5hbGwgJT4lIA0KICAgICAgICAgIHNlbGVjdChjb3VudHJ5LCByYW5raW5nLCBjb25maXJtZWQsIHJlY292ZXJlZCwgZGVhdGhzKSAlPiUgDQogICAgICAgICAgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzICYgY291bnRyeSAhPSAiV29ybGQiKSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBhcnJhbmdlKHJhbmtpbmcpICU+JSANCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgDQpnZHAudG9wMjAgJTw+JSByZW5hbWUoIkdEUCIgPSAiR0RQIChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpDQpnZHAudG9wMjANCg0KZyA8LSBnZ3Bsb3QoZ2RwLnRvcDIwLCBhZXMoeCA9IEdEUCwgeSA9IHJlb3JkZXIoY291bnRyeSwgLXJhbmtpbmcpKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShzdGF0ID0gImlkZW50aXR5IiwgYWVzKGZpbGwgPSBHRFApKSsgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoIkdEUCIsIGxvdyA9ICIjRkY0MDM4IiwgaGlnaCA9ICIjNTBFOTUyIikgKyANCiAgbGFicyh0aXRsZT1wYXN0ZTAoIkdEUCAgb2YgVG9wIDIwIENvdW50cmllcyBpbiAyMDE5IChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9R0RQLCB4ID0gR0RQKSwgc2l6ZT0zLjUsIGhqdXN0PS0wLjIpICsNCiAgeGxhYigiR0RQIChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpICsNCiAgeWxhYigiIikgDQpnDQoNCmdseS50b3AuZ2RwIDwtIGdncGxvdGx5KGcpDQpnbHkudG9wLmdkcA0KYGBgDQoNCg0KYGBge3J9DQpkZl9zYXJzIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIHNhcnNfMjAwMyIpKQ0KZGZfc2FycyA8LSBhcy5kYXRhLmZyYW1lKGRmX3NhcnMpDQpkZl9zYXJzDQoNCmRhdGVzLnMgPC0gZGZfc2Fyc1ssMV0lPiUgbWR5KCkNCnJhbmdlKGRhdGVzLnMpDQptaW4uZGF0ZS5zIDwtIG1pbihkYXRlcy5zKQ0KbWF4LmRhdGUucyA8LSBtYXgoZGF0ZXMucykNCm1pbi5kYXRlLnR4dC5zIDwtIG1pbi5kYXRlLnMgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KbWF4LmRhdGUudHh0LnMgPC0gbWF4LmRhdGUucyAlPiUgZm9ybWF0KCclZCAlYiAlWScpDQoNCmBgYA0KDQpgYGB7cn0NCiMgY2xlYW4gZGF0YSBTYXJzIA0KZGF0YS5zYXJzIDwtIGRmX3NhcnMgJT4lIHJlbmFtZShjKCJkYXRlIiA9ICJEYXRlIiwgImNvbmZpcm1lZCIgPSAiQ3VtdWxhdGl2ZV9udW1iZXIiICAsImRlYXRocyIgPSAiTnVtYmVyX2RlYXRocyIsICJyZWNvdmVyZWQiID0gIk51bWJlcl9yZWNvdmVyZWQiKSkgJT4lDQogIG11dGF0ZShkYXRlID0gZGF0ZSAlPiUgbWR5KCkpICU+JQ0KICBncm91cF9ieShjb3VudHJ5LCBkYXRlKSAlPiUgYXMuZGF0YS5mcmFtZSgpIA0KVmlldyhkYXRhLnNhcnMpDQoNCg0KIyBBZGQgV29ybGQncyBTYXJzIGNhc2VzIA0Kd29ybGQuc2FycyA8LSBkYXRhLnNhcnMgJT4lIGdyb3VwX2J5KGRhdGUpICU+JSANCiAgc3VtbWFyaXNlKGNvdW50cnk9J1dvcmxkJywNCiAgICAgICAgICAgIGNvbmZpcm1lZCA9IHN1bShjb25maXJtZWQsIG5hLnJtPVQpLA0KICAgICAgICAgICAgZGVhdGhzID0gc3VtKGRlYXRocywgbmEucm09VCksDQogICAgICAgICAgICByZWNvdmVyZWQgPSBzdW0ocmVjb3ZlcmVkLCBuYS5ybT1UKSkNCg0KZGF0YS5zYXJzICU8PiUgcmJpbmQod29ybGQuc2FycykNCmRhdGEuc2FycyAlPD4lIG11dGF0ZShjdXJyZW50LmNvbmZpcm1lZCA9IGNvbmZpcm1lZCAtIGRlYXRocyAtIHJlY292ZXJlZCkNCiNWaWV3KHdvcmxkLnNhcnMpIA0KI1ZpZXcoZGF0YS5zYXJzKSANCmBgYA0KDQpgYGB7cn0NCiNyYXRlDQpkYXRhLnNhcnMgJTw+JSBhcnJhbmdlKGNvdW50cnksIGRhdGUpDQpuIDwtIG5yb3coZGF0YS5zYXJzKQ0KZGF5MS5zYXJzIDwtIG1pbihkYXRhLnNhcnMkZGF0ZSkNCmRhdGEuc2FycyAlPD4lIG11dGF0ZShuZXcuY29uZmlybWVkID0gaWZlbHNlKGRhdGUgPT0gZGF5MSwgTkEsIGNvbmZpcm1lZCAtIGxhZyhjb25maXJtZWQsIG49MSkpLA0KICAgICAgICAgICAgICAgICBuZXcuZGVhdGhzID0gaWZlbHNlKGRhdGUgPT0gZGF5MSwgTkEsIGRlYXRocyAtIGxhZyhkZWF0aHMsIG49MSkpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKGRhdGUgPT0gZGF5MSwgTkEsIHJlY292ZXJlZCAtIGxhZyhyZWNvdmVyZWQsIG49MSkpKQ0KZGF0YS5zYXJzICU8PiUgbXV0YXRlKG5ldy5jb25maXJtZWQgPSBpZmVsc2UobmV3LmNvbmZpcm1lZCA8IDAsIDAsIG5ldy5jb25maXJtZWQpLA0KICAgICAgICAgICAgICAgICBuZXcuZGVhdGhzID0gaWZlbHNlKG5ldy5kZWF0aHMgPCAwLCAwLCBuZXcuZGVhdGhzKSwNCiAgICAgICAgICAgICAgICAgbmV3LnJlY292ZXJlZCA9IGlmZWxzZShuZXcucmVjb3ZlcmVkIDwgMCwgMCwgbmV3LnJlY292ZXJlZCkpDQojIyBkZWF0aCByYXRlIGJhc2VkIG9uIHRvdGFsIGRlYXRocyBhbmQgcmVjb3ZlcmVkIGNhc2VzDQpkYXRhLnNhcnMgJTw+JSBtdXRhdGUocmF0ZS51cHBlciA9ICgxMDAgKiBkZWF0aHMgLyAoZGVhdGhzICsgcmVjb3ZlcmVkKSkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLnVwcGVyID0gaWZlbHNlKGlzLm5hbihyYXRlLnVwcGVyKSwgMCwgcmF0ZS51cHBlcikpDQoNCiMjIGxvd2VyIGJvdW5kOiBkZWF0aCByYXRlIGJhc2VkIG9uIHRvdGFsIGNvbmZpcm1lZCBjYXNlcw0KZGF0YS5zYXJzICU8PiUgbXV0YXRlKHJhdGUubG93ZXIgPSAoMTAwICogZGVhdGhzIC8gY29uZmlybWVkKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUubG93ZXIgPSBpZmVsc2UoaXMubmFuKHJhdGUubG93ZXIpLCAwLCByYXRlLmxvd2VyKSkNCg0KIyMgZGVhdGggcmF0ZSBiYXNlZCBvbiB0aGUgbnVtYmVyIG9mIGRlYXRoL3JlY292ZXJlZCBvbiBldmVyeSBzaW5nbGUgZGF5DQpkYXRhLnNhcnMgJTw+JSBtdXRhdGUocmF0ZS5kYWlseSA9ICgxMDAgKiBuZXcuZGVhdGhzIC8gKG5ldy5kZWF0aHMgKyBuZXcucmVjb3ZlcmVkKSkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLmRhaWx5ID0gaWZlbHNlKGlzLm5hbihyYXRlLmRhaWx5KSwgMCwgcmF0ZS5kYWlseSkpDQoNClZpZXcoZGF0YS5zYXJzKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQNCmRhdGEuc2Fycy5sb25nIDwtIGRhdGEuc2FycyAlPiUNCiAgc2VsZWN0KGMoY291bnRyeSwgZGF0ZSwgY29uZmlybWVkLCBjdXJyZW50LmNvbmZpcm1lZCwgcmVjb3ZlcmVkLCBkZWF0aHMpKSAlPiUNCiAgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoY291bnRyeSwgZGF0ZSkpDQojIyBzZXQgZmFjdG9yIGxldmVscyB0byBzaG93IHRoZW0gaW4gYSBkZXNpcmFibGUgb3JkZXINCmRhdGEuc2Fycy5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLCBjb25maXJtZWQ9J1RvdGFsIENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY292ZXJlZD0nUmVjb3ZlcmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGhzPSdEZWF0aHMnKSkNClZpZXcoZGF0YS5zYXJzLmxvbmcpDQoNCiMgV29ybGQgc2FycycgbG9uZyBkYXRhIA0Kd29ybGQuc2Fycy5sb25nIDwtIGRhdGEuc2Fycy5sb25nICU+JQ0KICBmaWx0ZXIoY291bnRyeSA9PSAiV29ybGQiKQ0KVmlldyh3b3JsZC5zYXJzLmxvbmcpDQoNCmcgPC0gZ2dwbG90KHdvcmxkLnNhcnMubG9uZywgYWVzKGRhdGUsIGNvdW50LCBjb2xvciA9IHR5cGUpKSArDQogIGdlb21fbGluZSgpKw0KICBsYWJzKCJOdW1iZXIgb2YgQ2FzZXMgV29ybGR3aWRlOiBTQVJzIikrDQogIHhsYWIoIiIpKw0KICB5bGFiKCIiKQ0KZw0KDQpnbHkuZyA8LSBnZ3Bsb3RseShnKQ0KZ2x5LmcNCg0KZ2x5LnBsb3QyDQpgYGANCg0KDQpgYGB7cn0NCiMjIEN1cnJlbnQgQ29uZmlybWVkIENhc2VzDQpkYXRhLnNhcnMud29ybGQgPC0gZGF0YS5zYXJzICU+JSBmaWx0ZXIoY291bnRyeT09J1dvcmxkJykNClZpZXcoZGF0YS5zYXJzLndvcmxkKQ0KbiA8LSBucm93KGRhdGEuc2Fycy53b3JsZCkNClZpZXcoZGF0YS5zYXJzLndvcmxkKQ0KcGxvdDEgPC0gZ2dwbG90KGRhdGEuc2Fycy53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1jdXJyZW50LmNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0N1cnJlbnQgQ29uZmlybWVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdDIgPC0gZ2dwbG90KGRhdGEud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LmNvbmZpcm1lZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0RhaWx5IE5ldyBDb25maXJtZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQojIyBzaG93IHR3byBwbG90cyBzaWRlIGJ5IHNpZGUNCmdyaWQuYXJyYW5nZShwbG90MSwgcGxvdDIsIG5jb2w9MikNCmBgYA0KYGBge3J9DQojIyBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgc21vb3RoZWQgbGluZSBhbmQgdmVydGljYWwgeC1heGlzIGxhYmVscw0KcGxvdDEgPC0gZ2dwbG90KGRhdGEuc2Fycy53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1kZWF0aHMpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdBY2N1bXVsYXRpdmUgRGVhdGhzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdDIgPC0gZ2dwbG90KGRhdGEuc2Fycy53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1yZWNvdmVyZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdBY2N1bXVsYXRpdmUgUmVjb3ZlcmVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdDMgPC0gZ2dwbG90KGRhdGEuc2Fycy53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1uZXcuZGVhdGhzKSkgKw0KICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpICsNCiAgeGxhYignJykgKyB5bGFiKCdDb3VudCcpICsgbGFicyh0aXRsZT0nTmV3IERlYXRocycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCnBsb3Q0IDwtIGdncGxvdChkYXRhLnNhcnMud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LnJlY292ZXJlZCkpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J05ldyBSZWNvdmVyZWQgQ2FzZXMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQojIyBzaG93IGZvdXIgcGxvdHMgdG9nZXRoZXIsIHdpdGggMiBwbG90cyBpbiBlYWNoIHJvdw0KZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgcGxvdDMsIHBsb3Q0LCBucm93PTIpDQpgYGANCg0KYGBge3J9DQojZGZfdGhhaSA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBjb3ZpZF90aGFpbGFuZF91cGRhdGVkIikpDQojZGZfdGhhaSA8LSBhcy5kYXRhLmZyYW1lKGRmX3RoYWkpDQoNCmRmX3RoYWkgPC0gcmVhZF9jc3YoIkQ6LzRELTIvUHJvamVjdCAyL0RhdGEvY292aWRfdGhhaWxhbmRfdXBkYXRlZC5jc3YiKQ0KU3lzLnNldGxvY2FsZSgiTENfQ1RZUEUiLCAiVGhhaSIpDQpvcHRpb25zKGVuY29kaW5nID0gIlVURi04IikNCiNWaWV3KGRmX3RoYWkpDQoNCmRhdGVzLnRoIDwtIGRmX3RoYWlbLDJdJT4lIG1keSgpDQpyYW5nZShkYXRlcy50aCkNCm1pbi5kYXRlLnRoIDwtIG1pbihkYXRlcy50aCkNCm1heC5kYXRlLnRoIDwtIG1heChkYXRlcy50aCkNCm1pbi5kYXRlLnR4dC50aCA8LSBtaW4uZGF0ZS50aCAlPiUgZm9ybWF0KCclZCAlYiAlWScpDQptYXguZGF0ZS50eHQudGggPC0gbWF4LmRhdGUudGggJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KDQpkZl90aGFpJGFubm91bmNlX2RhdGUgPC0gbWR5KGRmX3RoYWkkYW5ub3VuY2VfZGF0ZSkNCmRmX3RoYWkkbm90aWZpY2F0aW9uX2RhdGUgPC0gbWR5KGRmX3RoYWkkbm90aWZpY2F0aW9uX2RhdGUpDQpkZl90aGFpDQoNCmRmX3RoYWkgPC0gZGZfdGhhaSAlPiUgc2VsZWN0KCFOby4pICU+JSANCiAgZ3JvdXBfYnkoYW5ub3VuY2VfZGF0ZSkNCmRmX3RoYWkNCmBgYA0KYGBge3J9DQojIFRvdGFsIGNvbmZpcm1lZCBjYXNlcyBpbiBUaGFpbGFuZA0KZGF0YS50aGFpLmNvdW50IDwtIGRmX3RoYWkgJT4lDQogIHNlbGVjdChhbm5vdW5jZV9kYXRlKSAlPiUNCiAgc3VtbWFyaXNlKGNvbWZpcm1lZCA9IG4oKSkgICU+JSBhcy5kYXRhLmZyYW1lKCkNCmRhdGEudGhhaS5jb3VudA0KDQpkYXRhLnRoYWkuY291bnQkY3VtdWxhdGl2ZV9jb25maXJtZWQgPC0gY3Vtc3VtKGRhdGEudGhhaS5jb3VudFssIDJdKQ0KZGF0YS50aGFpLmNvdW50IA0KDQpnLnRoIDwtIGdncGxvdChkYXRhLnRoYWkuY291bnQpICsgDQogIGdlb21fbGluZShhZXMoeCA9IGFubm91bmNlX2RhdGUsIHkgPSBjdW11bGF0aXZlX2NvbmZpcm1lZCkpICsNCiAgbGFicyh0aXRsZSA9ICJUaGFpIENvbmZpcm1lZCBDYXNlcyAoSmFuIDIwMjAgLSBKYW4gMjAyMSkiKSArDQogIHhsYWIoIkRhdGUgKEFubm91bmNlIERhdGUpIikgKyANCiAgeWxhYigiQ29uZmlybWVkIENhc2VzIikNCg0KZy50aA0KDQpnbHkudGggPC0gZ2dwbG90bHkoZy50aCkNCmdseS50aA0KYGBgDQoNCmBgYHtyfQ0KIyBDb25maXJtZWQgY2FzZXMgZGl2aWRlZCBieSBzZXggKGdlbmRlcikNCmRhdGEudGhhaS5nZW5kZXIgPC0gZGZfdGhhaSAlPiUNCiAgZ3JvdXBfYnkoc2V4KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgbXV0YXRlKHBlcmNlbnQgPSAoY291bnQgLyBzdW0oY291bnQpICogMTAwKSAlPiUgcm91bmQoMikpICU+JQ0KICAjbXV0YXRlKHBvcyA9IGN1bXN1bShwZXJjZW50KSAtIDAuNSpwZXJjZW50KSAlPiUNCiAgYXJyYW5nZShkZXNjKHBlcmNlbnQpKQ0KZGF0YS50aGFpLmdlbmRlcg0KDQpkYXRhLnRoYWkuZ2VuZGVyJHNleCA8LSBmYWN0b3IoZGF0YS50aGFpLmdlbmRlciRzZXgsIGxldmVscyA9IGFzLmNoYXJhY3RlcihkYXRhLnRoYWkuZ2VuZGVyJHNleCkpDQpkYXRhLnRoYWkuZ2VuZGVyJHNleA0KDQpnLnRoLmdlbmRlciA8LSBkYXRhLnRoYWkuZ2VuZGVyICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gIiIsIHkgPSBwZXJjZW50LCBmaWxsID0gc2V4KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKCJ5IikgKw0KICB0aGVtZV92b2lkKCkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHBlcmNlbnQsICIlIikpLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA1LCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkpIA0KDQpnLnRoLmdlbmRlcg0KDQpgYGANCg0KYGBge3J9DQojIENvbmZpcm1lZCBjYXNlcyBkaXZpZGVkIGJ5IGFnZQ0KZGF0YS50aGFpLmFnZSA8LSBkZl90aGFpICU+JQ0KICBncm91cF9ieShhZ2UpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoY291bnQpKQ0KZGF0YS50aGFpLmFnZQ0KYGBgDQoNCmBgYHtyfQ0KIyBDb25maXJtZWQgY2FzZXMgZGl2aWRlZCBieSBuYXRpb25hbGl0eQ0KZGF0YS50aGFpLm5hdGlvbmFsaXR5IDwtIGRmX3RoYWkgJT4lDQogIGdyb3VwX2J5KG5hdGlvbmFsaXR5KSAlPiUNCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGNvdW50KSkNCmRhdGEudGhhaS5uYXRpb25hbGl0eQ0KYGBgDQoNCg0KDQpgYGB7cn0NCm1lcmdjb3VudHJ5ID0gZnVuY3Rpb24oZGF0YTEsZGF0YTIpew0KICBkYXRhIDwtIG1lcmdlKHggPSBkYXRhMSwgeSA9IGRhdGEyLCBieSA9ICJjb3VudHJ5IiwgYWxsLnggPSBUUlVFKSANCiAgcmV0dXJuKGRhdGEpDQp9DQpkYXRhLnRvcC53b3JsZCA8LSBtZXJnZSh4ID0gZGF0YS50b3AsIHkgPSBkZl9nZHAyMDE5LCBieSA9ICJjb3VudHJ5IiwgYWxsLnggPSBUUlVFKSAlPiUgDQogIHNlbGVjdCgtYyhjb2RlLHJhbmssbmV3LmNvbmZpcm1lZCxuZXcuZGVhdGhzLGN1cnJlbnQuY29uZmlybWVkLHBvcHVsYXRpb24pKSAlPiUgDQogIHJlbmFtZShHRFA9IkdEUCAobWlsbGlvbnMgb2YgVVMgZG9sbGFycykiKQ0KDQpkYXRhLnRvcC53b3JsZCA8LSBtZXJnZSh4ID0gZGF0YS50b3Aud29ybGQsIHkgPSBkZl9oZWFsdCwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgJT4lDQogIHJlbmFtZShoZWFsdGhjYXJlPSJoZWFsdGhDYXJlSW5kZXgiKQ0KDQpkYXRhLnRvcC53b3JsZCA8LSBtZXJnZSh4ID0gZGF0YS50b3Aud29ybGQsIHkgPSBkZl9wb3JuaHViLCBieSA9ICJjb3VudHJ5IiwgYWxsLnggPSBUUlVFKSAlPiUNCiAgcmVuYW1lKFBvcm5odWIgPSAiUG9ybmh1YkluZGV4KCUpIikNCg0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2NvdW50cnkoZGF0YS50b3Aud29ybGQsIGRmX3RlbXApDQppbmRleCA8LSBpcy5uYShkYXRhLnRvcC53b3JsZCkNCmRhdGEudG9wLndvcmxkW2luZGV4XSA8LSAwDQpkYXRhLnRvcC53b3JsZA0KI1ZpZXcoZGF0YS50b3Aud29ybGQpDQoNCm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKGRhdGEpew0KICAjcmV0dXJuICgoZGF0YSAtIG1pbihkYXRhLG5hLnJtID0gVFJVRSkpLyhtYXgoZGF0YSxuYS5ybSA9IFRSVUUpIC0gbWluKGRhdGEsbmEucm0gPSBUUlVFKSkpDQogIHogPC0gc2NhbGUoZGF0YSk7DQogIHRhbmgoei8yKQ0KfQ0KDQpub3JtX2RhdGEgPSBhcy5kYXRhLmZyYW1lKGFwcGx5KGRhdGEudG9wLndvcmxkWywyOjEyXSwyLG5vcm1hbGl6ZSkpDQpjb3JyX2RhdGEgPC0gbm9ybV9kYXRhDQpub3JtX2RhdGEkY291bnRyeSA8LSBjKCJBcmdlbnRpbmEiLCJCYW5nbGFkZXNoIiwiQnJhemlsIiwiQ2hpbGUiLCJDb2xvbWJpYSIsIkZyYW5jZSIsIkdlcm1hbnkiLCJJbmRpYSIsIklyYW4iLCJJdGFseSIsIk1leGljbyIsIlBha2lzdGFuIiwiUGVydSIsIlJ1c3NpYSIsInNhdWRpIEFyYWJpYSIsIlNvdXRoIEFmcmljYSIsIlNwYWluIiwiVHVya2V5IiwiVW5pdGVkIEtpbmdkb20iLCJVUyIpDQpWaWV3KG5vcm1fZGF0YSkNCm5vcm1fZGF0YV9wbG90IDwtIHNlbGVjdChub3JtX2RhdGEsImNvdW50cnkiLCJjb25maXJtLnJhdGUiLCJkZWF0aC5yYXRlIiwicmVjb3Zlci5yYXRlIiwiaGVhbHRoY2FyZSIsIlBvcm5odWIiLCJHRFAiLCJhdmdfdGVtcCIpDQpub3JtX2RhdGFfcGxvdCAlPD4lIGdhdGhlcihrZXk9dHlwZSwgdmFsdWU9Y291bnQsIC1jKGNvdW50cnkpKQ0KbGV2ZWxfb3JkZXIgPC0gZmFjdG9yKG5vcm1fZGF0YV9wbG90JHR5cGUsIA0KICAgICAgICAgICAgICAgICAgICAgIGxldmVsID0gYygiR0RQIiwiYXZnX3RlbXAiLCJoZWFsdGhjYXJlIiwicmVjb3Zlci5yYXRlIiwiZGVhdGgucmF0ZSIsImNvbmZpcm0ucmF0ZSIsIlBvcm5odWIiKSkNCmdncGxvdChkYXRhID0gbm9ybV9kYXRhX3Bsb3QsIGFlcyh4PWNvdW50cnksIHk9bGV2ZWxfb3JkZXIsIGZpbGw9Y291bnQpKSArIA0KICBnZW9tX3RpbGUoKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gInBpbmsiLCBoaWdoID0gImJsdWUiKSArDQogIHhsYWIoIiIpICsNCiAgeWxhYigiIikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCx2anVzdCA9IDEpKSsNCiAgdGhlbWUoDQogICAgYXhpcy5saW5lID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLA0KICAgICNsZWdlbmQucG9zaXRpb24gPSAibm9uZSINCiAgKQ0KYGBgDQoNCg0KYGBge3J9DQojY29ycmVsYXRpb24NCmNvcnJfZGF0YSAlPD4lIHNlbGVjdChjKEdEUCxjb25maXJtLnJhdGUsZGVhdGgucmF0ZSxyZWNvdmVyLnJhdGUsIGhlYWx0aGNhcmUsIGF2Z190ZW1wLCBQb3JuaHViKSkNCmhlYWQoY29ycl9kYXRhKQ0KY29yKGNvcnJfZGF0YSkNCmdnY29ycnBsb3QoY29yKGNvcnJfZGF0YSksaGMub3JkZXIgPSBUUlVFLA0KICAgICAgICAgICBvdXRsaW5lLmNvbG9yID0gIndoaXRlIiwNCiAgICAgICAgICAgY29sb3JzID0gYygiIzZEOUVDMSIsIndoaXRlIiwiI0U0NjcyNiIpLA0KICAgICAgICAgICBsYWIgPSBUUlVFKQ0KYGBgDQoNCg0KDQo=